package com.eistert.java.datastructure._01_Array;

/**
 * customize the array
 *
 * @Author: ai
 * @create: 2023-04-04 07:38
 */
public class _01_Array<E> {
    private E[] data;
    private int size;

    public _01_Array(int capacity) {
        data = (E[]) new Object[capacity];
        size = 0;
    }

    public _01_Array() {
        this(10);
    }

    public _01_Array(E[] arr) {
        data = (E[]) new Object[arr.length];
        for (int i = 0; i < arr.length; i++)
            data[i] = arr[i];
        size = arr.length;
    }

    public int getCapacity() {
        return data.length;
    }

    public int getSize() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    /**
     * wrong：
     * transition
     * insert a new element into a array,at a specify position
     * <p>
     * ==>
     * right：
     * translation:
     * <p>
     * insert a new element into the array at the specified position
     */
    public void add(int index, E e) {
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("Add failed,Required index >= 0 and index <= size");
        }

        if (size == data.length) {
            resize(2 * data.length);
        }

        /**
         * wrong:
         * all the element after the array index of element move back a step,data[index] equal to the original element
         *
         * ==>
         *right:
         * All elements after the index position in the array are moved back one position
         *
         * data[index] equal to the original element
         */
        for (int i = size - 1; i >= index; i--) {
            data[i + 1] = data[i];
        }

        data[index] = e;

        size++;
    }

    /**
     * reuse the add method
     * add a element at the last index of the array
     */
    public void addLast(E e) {
        add(size, e);
    }


    /**
     * reuse the add method
     * add a element at the first index of the array
     */
    public void addFirst(E e) {
        add(0, e);
    }

    public E get(int index) {
        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("get failed,index is illegal.");
        }
        return data[index];
    }


    public void set(int index, E e) {
        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("set failed,index is illegal.");
        }

        data[index] = e;
    }


    public boolean contains(E e) {
        for (int i = 0; i < size; i++) {
            if (data[i].equals(e)) {
                return true;
            }
        }

        return false;
    }


    public int find(E e) {
        for (int i = 0; i < size; i++) {
            if (data[i].equals(e)) {
                return i;
            }
        }
        return -1;
    }


    /**
     * remove specified position element in the array.
     * <p>
     * Removes the specified object from the array
     *
     * @param index specified object index
     * @return removed the element
     */
    public E remove(int index) {
        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("remove failed,index is illegal.");
        }

        E ret = data[index];

        for (int i = index + 1; i < size; i++) {
            data[i - 1] = data[i];
        }

        size--;
        data[size] = null; // loitering objects != memory leak

        /**
         * The array capacity is occupied by a quarter
         *
         *
         * data.length / 2 != 0
         *
         */
        if (size == data.length / 4 && data.length / 2 != 0) {
            resize(data.length / 2);
        }

        return ret;
    }


    // 从数组中删除第一个元素, 返回删除的元素

    /**
     * remove the first element from the array
     *
     * @return
     */
    public E removeFirst() {
        return remove(0);
    }

    /**
     * get first element from the array
     *
     * @return
     */
    public E getFirst() {
        return get(0);
    }

    /**
     * get last element from the array
     *
     * @return
     */
    public E getLast() {
        return get(size - 1);
    }

    // 从数组中删除最后一个元素, 返回删除的元素

    /**
     * remove the last element from the array
     *
     * @return the removed element
     */
    public E removeLast() {
        return remove(size - 1);
    }

    // 从数组中删除元素e

    /**
     * remove element from the array
     *
     * @param e The element to remove
     */
    public void removeElement(E e) {
        int index = find(e);
        if (index != -1)
            remove(index);
    }

    /**
     * wrong:
     * resize the original array capacity to the newCapacity
     * <p>
     * ==》
     *
     * <p>
     * right:
     * Enlarge the original array capacity to twice the original size
     *
     * @param newCapacity
     */
    private void resize(int newCapacity) {
        E[] newData = (E[]) new Object[newCapacity];

        for (int i = 0; i < size; i++) {
            newData[i] = data[i];
        }

        data = newData;
    }

    public void swap(int i, int j) {

        if (i < 0 || i >= size || j < 0 || j >= size)
            throw new IllegalArgumentException("Index is illegal.");

        E t = data[i];
        data[i] = data[j];
        data[j] = t;
    }

    /**
     * print the array
     *
     * @return
     */
    @Override
    public String toString() {

        StringBuilder res = new StringBuilder();
        res.append(String.format("Array: size = %d , capacity = %d\n", size, data.length));
        res.append('[');
        for (int i = 0; i < size; i++) {
            res.append(data[i]);
            if (i != size - 1)
                res.append(", ");
        }
        res.append(']');
        return res.toString();
    }
}
